/*
 * Copyright © OpenAtom Foundation.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package io.iec.edp.caf.generator.baseInfo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import io.iec.edp.caf.generator.compileunit.CompileUnitGeneratorContext;
import org.eclipse.jdt.core.dom.*;

/**
 * @author liu_wei
 */
public class TypeInfo extends BaseGenerateInfo {

    private String typeName;

    private String typePackageName;
    private Boolean isParameterizedType = false;
    private List<TypeInfo> arguments = new ArrayList<TypeInfo>();
    private boolean isArray = false;
    private boolean isPrimitive = true;

    public TypeInfo(String typeName) {
        if (typeName == null || typeName.equals(""))
            throw new RuntimeException("typeName不能为空。");
//            if(typeName.contains("."))
//            throw new RuntimeException("不正确的type格式"+typeName);
        this.typeName = typeName;
    }

    public TypeInfo(Class type) {

        typeName = type.getSimpleName();
        if (type.getPackage() != null) {
            typePackageName = type.getPackage().getName();
        }
        isArray = type.isArray();
//		isParameterizedType = type.gen
    }

    public List<TypeInfo> getArguments() {
        return arguments;
    }

    public void setArguments(List<TypeInfo> arguments) {
        this.arguments = arguments;
    }

    public String getTypeName() {
        return typeName;
    }

    public void setTypeName(String typeName) {
        this.typeName = typeName;
    }

    public void setIsParameterizedType(Boolean isParameterizedType) {
        this.isParameterizedType = isParameterizedType;
    }

    public String getTypePackageName() {
        return typePackageName;
    }

    public void setTypePackageName(String typePackageName) {
        this.typePackageName = typePackageName;
    }

    public boolean isArray() {
        return isArray;
    }

    public void setArray(boolean isArray) {
        this.isArray = isArray;
    }

    public Type getType(AST ast) {

        Type baseType;
        Type primitiveType = getPrimitiveType(ast);
        if (isPrimitive)
            baseType = primitiveType;
        else
            baseType = ast.newSimpleType(ast.newName(typeName));
        if (isParameterizedType) {
            ParameterizedType parameterizedType = ast.newParameterizedType(baseType);
            for (TypeInfo typeInfo : arguments) {
                parameterizedType.typeArguments().add(typeInfo.getType(ast));
            }
            return parameterizedType;
        }
        if (isArray) {
            return ast.newArrayType(baseType);
        }
        return baseType;
    }

    public Type getType(AST ast, CompileUnitGeneratorContext context) {
        Type primitiveType = getPrimitiveType(ast);
        if (isPrimitive)
            return primitiveType;

        setImport(context);
        SimpleType baseType = ast.newSimpleType(ast.newName(typeName));
        if (!isParameterizedType)
            return baseType;
        ParameterizedType parameterizedType = ast.newParameterizedType(baseType);
        for (TypeInfo typeInfo : arguments) {
            parameterizedType.typeArguments().add(typeInfo.getType(ast, context));
        }
        return parameterizedType;
    }

    private void setImport(CompileUnitGeneratorContext context) {
        if (typePackageName == null || "".equals(typePackageName))
            return;
        context.addImport(typePackageName + "." + typeName);
    }

    private Type getPrimitiveType(AST ast) {
        isPrimitive = true;
        switch (typeName) {
            case "int":
                return ast.newPrimitiveType(PrimitiveType.INT);
            case "char":
                return ast.newPrimitiveType(PrimitiveType.CHAR);
            case "boolean":
                return ast.newPrimitiveType(PrimitiveType.BOOLEAN);
            case "short":
                return ast.newPrimitiveType(PrimitiveType.SHORT);
            case "long":
                return ast.newPrimitiveType(PrimitiveType.LONG);
            case "float":
                return ast.newPrimitiveType(PrimitiveType.FLOAT);
            case "double":
                return ast.newPrimitiveType(PrimitiveType.DOUBLE);
            case "byte":
                return ast.newPrimitiveType(PrimitiveType.BYTE);
            case "void":
            case "Void":
                return ast.newPrimitiveType(PrimitiveType.VOID);
            default:
                isPrimitive = false;
                return null;
        }
    }

    @Override
    public boolean equals(Object obj) {
        TypeInfo typeInfo = (TypeInfo) obj;
        if (typeInfo == null)
            return false;

        if (this.typeName != typeInfo.typeName)
            return false;

        if (this.isParameterizedType != typeInfo.isParameterizedType)
            return false;
        if (!this.isParameterizedType)
            return true;

        if (this.arguments.size() != typeInfo.arguments.size())
            return false;

        for (int i = 0; i < this.arguments.size(); i++) {
            TypeInfo arg = this.arguments.get(i);
            TypeInfo typeArg = typeInfo.arguments.get(i);
            if (!arg.equals(typeArg))
                return false;
        }
        return true;
    }

    @Override
    void generate() {

    }

    public String getTypeFullName() {
        if (typePackageName == null || "".equals(typePackageName))
            return null;
        return typePackageName + "." + typeName;
    }

    //region 常用TypeInfo
    public static TypeInfo getArrayListOfStringInfo() {
        TypeInfo result = new TypeInfo(ArrayList.class);
        result.setIsParameterizedType(true);
        result.setArguments(new ArrayList<TypeInfo>(Arrays.asList(new TypeInfo[]{new TypeInfo(String.class)})));
        return result;
    }
    //endregion
}
